// -*- C++ -*------------------------------------------------------------------
//  $Id: IoTools.cc,v 1.5 2008-05-09 13:58:50 biocomp Exp $
//
//  Class:              Atom
//
//  Base Class(es):     -
//
//  Derived Class(es):  -
//
//  Containing:         -
//
//  Author:             Silvio Tosatto
//
//  Project Name:       Biopool, Victor
//
//  Date:               01/98, 08/99
//
//  Reviewed By:        <Name>
//
//  Description:
//    Library of auxiliary I/O functions 
//
// ---------------------------------------------------------------------------
 
#include <iostream>
#include <iomanip>
#include <fstream>
#include <ctype.h>
#include <IoTools.h>

// -*- C++ -*-----------------------------------------------------------------
//
//  Author: Silvio Tosatto 
//
//  Project Name: Biopool
//
//  Date: 12/97
//
//  Class:-
//  
//  Function: readOnSameLine
//
//  Description:  Function tries to read and return an int from the 
//  same input line. (as delimited by '\n')
//
//  Precondition:  Stream must be opened.
//
//  Postcondition:  Returns the int if it existed or 0 otherwise.
//
//  Error handling: -
//
// ----------------------------------------------------------------------------

template<class T> int readOnSameLine(istream& is, T& result)
{
  char c;
  do {
    is.get(c);
	// number found:
	if (isdigit(c) || (c == '-')) {
	  is.putback(c);
	  is >> result;
	  return 1;
  	}
  } while ((!is.eof()) && (c != '\n') && ((c == ' ') || (c == '\t')));
  // no number on line:
  return 0;
}

template int readOnSameLine<unsigned int>(istream& is, unsigned int& result);
template int readOnSameLine<double>(istream& is, double& result);

// -*- C++ -*-----------------------------------------------------------------
//
//  Author: Silvio Tosatto 
//
//  Project Name: Biopool
//
//  Date: 12/97
//
//  Class:-
//  
//  Function: checkForBlankLine
//
//  Description:  Function checks if next line is blank. 
//  (ie. whitespace only)
//
//  Precondition:  Stream must be opened.
//
//  Postcondition:  Returns 1 if the next line is blank, 0 otherwise.
//
//  Error handling: -
//
// ----------------------------------------------------------------------------

int checkForBlankLine(istream& is, bool returnbuffer)
{
  char c;
  // already at end of file?
  if (is.eof())
    return 0;	
  do {
    is.get(c);
    // line is blank:
    if (c == '\n')
      return 1;
  } while ((!is.eof()) && ((c == ' ') || (c == '\t')));
  // line is not blank:
  if ( returnbuffer )
    is.putback(c);
  return 0;
}

// checks if keyword is present at current position in stream
int checkForKeyword(istream& is, string key)
{
  eatComment(is);
  char c;
  // already at end of file?
  if (is.eof())
    return 0;	
  is.get(c);
  // found key?:
  if (c == key[0])
    {
      string tmp;
      is >> tmp;
      if (key == (c+tmp))
	return 1;
    }
  else
    is.putback(c);
  return 0;
}

// reads until newline is found
void skipToNewLine(istream& is)
{
  char c;
  do {
    is.get(c);
  } while((!is.eof()) && (c != '\n'));
}

// skips over whitespace
void eatWhite(istream& is)
{
  char c;
  while(is.get(c)) {
    if (!isspace(c)) {
      is.putback(c);
      break;
    }
  }
}


// skips over comments (starting with '#')
void eatComment(istream& is)
{
  char c;
  do {
    eatWhite(is);
    is.get(c);
    if (c != '#') {
      is.putback(c);
      break;
    }
    skipToNewLine(is); // search next new line
  }
  while (!is.eof());
}

// peek if number follows, if so return it (1) else not (0)
template<class T> int readNumber(istream& is, T& result)
{
  result = 0;
  eatComment(is);
  char c;
  is.get(c);
  // number found:
  if (isdigit(c) || (c == '-')) 
    {
      is.putback(c);
      is >> result;
      return 1;
    }
  // no number on line:
  is.putback(c);
  return 0;
}

template int readNumber<int>(istream& is, int& result);

// read a whole line into a string
string readLine(istream& is)
{
  string str = "";
  eatComment(is);
  char c;
  while(is.get(c)) 
    {
      if ((c == '\n') || (c == '\r')) 
	break;
      else 
	str = str + c;
    }
  return str;
}


// writes a vgVector3 in one statement
template<class T> ostream& operator <<(ostream &os, const vgVector3<T> &vec)
{
  unsigned old_prec = os.precision();
  ios::fmtflags old_flags = os.flags();
  os.setf(ios::fixed, ios::floatfield);

  os << setw(8) << setprecision(3) << vec[0] << "   " 
     << setw(8) << setprecision(3) << vec[1] << "   " 
     << setw(8) << setprecision(3) << vec[2];

  os.precision(old_prec);
  os.flags(old_flags);
  return os;
}

template ostream& operator <<<double>(ostream &os, const vgVector3<double> &vec);


// reads a vgVector3 in one statement
template<class T> istream& operator >>(istream &is, vgVector3<T> &vec)
{
  is >> vec[0] >> vec[1] >> vec[2];
  return is;
}

template istream& operator >><double>(istream &is, vgVector3<double> &vec);

// writes a vgVector3 in one statement
template<class T> ostream& operator <<(ostream &os, const vgMatrix3<T> &vec)
{
  unsigned old_prec = os.precision();
  ios::fmtflags old_flags = os.flags();
  os.setf(ios::fixed, ios::floatfield);

  os << setw(8) << setprecision(3) << vec[0] << "   " 
     << setw(8) << setprecision(3) << vec[1] << "   " 
     << setw(8) << setprecision(3) << vec[2];
  os << setw(8) << setprecision(3) << vec[3] << "   " 
     << setw(8) << setprecision(3) << vec[4] << "   " 
     << setw(8) << setprecision(3) << vec[5];
  os << setw(8) << setprecision(3) << vec[6] << "   " 
     << setw(8) << setprecision(3) << vec[7] << "   " 
     << setw(8) << setprecision(3) << vec[8];

  os.precision(old_prec);
  os.flags(old_flags);
  return os;
}

template ostream& operator <<<double>(ostream &os, const vgMatrix3<double> &vec);


// reads a vgVector3 in one statement
template<class T> istream& operator >>(istream &is, vgMatrix3<T> &vec)
{
  is >> vec[0] >> vec[1] >> vec[2];
  is >> vec[3] >> vec[4] >> vec[5];
  is >> vec[6] >> vec[7] >> vec[8];
  return is;
}

template istream& operator >><double>(istream &is, vgMatrix3<double> &vec);
